<!DOCTYPE html>
<html lang="zh-CN" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>进程管理 - 命令行执行器</title>
    
    <!-- Bootstrap CSS -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
    <!-- Font Awesome -->
    <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
    <!-- SockJS and STOMP -->
    <script src="https://cdn.jsdelivr.net/npm/sockjs-client@1/dist/sockjs.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/stompjs@2.3.3/lib/stomp.min.js"></script>
    
    <style>
        :root {
            --primary-color: #6366f1;
            --secondary-color: #8b5cf6;
            --success-color: #10b981;
            --warning-color: #f59e0b;
            --danger-color: #ef4444;
            --dark-color: #1f2937;
            --light-color: #f9fafb;
        }
        
        body {
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            min-height: 100vh;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
        }
        
        .main-container {
            background: rgba(255, 255, 255, 0.95);
            backdrop-filter: blur(10px);
            border-radius: 20px;
            box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
            margin: 2rem auto;
            max-width: 1400px;
            overflow: hidden;
        }
        
        .header-section {
            background: linear-gradient(135deg, var(--primary-color), var(--secondary-color));
            color: white;
            padding: 2rem;
        }
        
        .btn-gradient {
            background: linear-gradient(135deg, var(--primary-color), var(--secondary-color));
            border: none;
            border-radius: 25px;
            color: white;
            font-weight: 600;
            padding: 12px 30px;
            transition: all 0.3s ease;
        }
        
        .btn-gradient:hover {
            background: linear-gradient(135deg, var(--secondary-color), var(--primary-color));
            color: white;
            transform: translateY(-2px);
            box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2);
        }
        
        .status-badge {
            border-radius: 20px;
            font-size: 0.8rem;
            font-weight: 600;
            padding: 5px 15px;
        }
        
        .status-running {
            background-color: var(--success-color);
            color: white;
        }
        
        .status-stopped {
            background-color: var(--danger-color);
            color: white;
        }
        
        .status-error {
            background-color: var(--warning-color);
            color: white;
        }
        
        .status-starting {
            background-color: var(--primary-color);
            color: white;
        }
        
        .status-stopping {
            background-color: var(--secondary-color);
            color: white;
        }
        
        .log-container {
            background: var(--dark-color);
            border-radius: 10px;
            color: #e5e7eb;
            font-family: 'Courier New', monospace;
            font-size: 0.9rem;
            height: 400px;
            overflow-y: auto;
            padding: 1rem;
        }
        
        .log-entry {
            margin-bottom: 0.5rem;
            padding: 0.25rem 0;
            border-bottom: 1px solid #374151;
        }
        
        .log-timestamp {
            color: #9ca3af;
            font-size: 0.8rem;
        }
        
        .log-level-info {
            color: #10b981;
        }
        
        .log-level-error {
            color: #ef4444;
        }
        
        .log-level-warn {
            color: #f59e0b;
        }
        
        .command-input {
            background: var(--light-color);
            border: 2px solid #e5e7eb;
            border-radius: 10px;
            font-family: 'Courier New', monospace;
            padding: 1rem;
            transition: border-color 0.3s ease;
        }
        
        .command-input:focus {
            border-color: var(--primary-color);
            box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.1);
        }
        
        .process-card {
            background: white;
            border-radius: 15px;
            box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
            margin-bottom: 1rem;
            overflow: hidden;
            transition: transform 0.3s ease;
        }
        
        .process-card:hover {
            transform: translateY(-2px);
        }
        
        .process-header {
            background: linear-gradient(135deg, #f8fafc, #e2e8f0);
            padding: 1rem;
        }
        
        .process-body {
            padding: 1rem;
        }
        
        .animate-pulse {
            animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
        }
        
        @keyframes pulse {
            0%, 100% {
                opacity: 1;
            }
            50% {
                opacity: .5;
            }
        }
        
        .sidebar {
            background: var(--light-color);
            border-radius: 15px;
            padding: 1.5rem;
            height: fit-content;
        }
        
        .toast-container {
            position: fixed;
            top: 20px;
            right: 20px;
            z-index: 1050;
        }
        
        .custom-toast {
            background: white;
            border-radius: 10px;
            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
            margin-bottom: 10px;
            padding: 1rem;
            min-width: 300px;
        }
        
        .loading-spinner {
            display: inline-block;
            width: 20px;
            height: 20px;
            border: 3px solid #f3f3f3;
            border-top: 3px solid var(--primary-color);
            border-radius: 50%;
            animation: spin 1s linear infinite;
        }
        
        @keyframes spin {
            0% { transform: rotate(0deg); }
            100% { transform: rotate(360deg); }
        }
    </style>
</head>
<body>
    <div class="main-container">
        <!-- Header Section -->
        <div class="header-section">
            <div class="d-flex justify-content-between align-items-center">
                <div>
                    <h1 class="mb-0">
                        <i class="fas fa-terminal me-3"></i>
                        进程管理
                    </h1>
                    <p class="mb-0 mt-2 opacity-75">实时监控和管理命令行进程</p>
                </div>
                <div>
                    <a href="/" class="btn btn-outline-light me-2">
                        <i class="fas fa-home me-1"></i>
                        首页
                    </a>
                    <a href="/swagger-ui.html" class="btn btn-outline-light" target="_blank">
                        <i class="fas fa-book me-1"></i>
                        API文档
                    </a>
                </div>
            </div>
        </div>
        
        <!-- Main Content -->
        <div class="container-fluid p-4">
            <div class="row">
                <!-- Sidebar -->
                <div class="col-lg-4">
                    <div class="sidebar">
                        <h4 class="mb-3">
                            <i class="fas fa-play-circle me-2"></i>
                            执行命令
                        </h4>
                        
                        <form id="commandForm">
                            <div class="mb-3">
                                <label for="processName" class="form-label">进程名称</label>
                                <input type="text" class="form-control" id="processName" 
                                       placeholder="例如：FFmpeg视频转换" required>
                            </div>
                            
                            <div class="mb-3">
                                <label for="command" class="form-label">命令</label>
                                <textarea class="form-control command-input" id="command" rows="4" 
                                          placeholder="输入要执行的命令..." required></textarea>
                            </div>
                            
                            <div class="mb-3">
                                <label class="form-label">快速命令</label>
                                <div class="d-grid gap-2">
                                    <button type="button" class="btn btn-outline-primary btn-sm" 
                                            onclick="setQuickCommand('ffmpeg -i input.mp4 -c:v libx264 -c:a aac output.mp4', 'FFmpeg视频转换')">
                                        <i class="fas fa-video me-1"></i>
                                        FFmpeg转换
                                    </button>
                                    <button type="button" class="btn btn-outline-success btn-sm" 
                                            onclick="setQuickCommand('python datax.py /path/to/job.json', 'DataX数据同步')">
                                        <i class="fas fa-database me-1"></i>
                                        DataX同步
                                    </button>
                                    <button type="button" class="btn btn-outline-warning btn-sm" 
                                            onclick="setQuickCommand(getPingCommand(), '网络测试')">
                                        <i class="fas fa-network-wired me-1"></i>
                                        网络测试
                                    </button>
                                </div>
                            </div>
                            
                            <button type="submit" class="btn btn-gradient w-100" id="executeBtn">
                                <i class="fas fa-rocket me-2"></i>
                                执行命令
                            </button>
                        </form>
                        
                        <hr class="my-4">
                        
                        <h5 class="mb-3">
                            <i class="fas fa-chart-bar me-2"></i>
                            统计信息
                        </h5>
                        <div class="row text-center">
                            <div class="col-4">
                                <div class="border rounded p-2">
                                    <div class="h4 mb-0 text-success" id="runningCount">0</div>
                                    <small class="text-muted">运行中</small>
                                </div>
                            </div>
                            <div class="col-4">
                                <div class="border rounded p-2">
                                    <div class="h4 mb-0 text-danger" id="stoppedCount">0</div>
                                    <small class="text-muted">已停止</small>
                                </div>
                            </div>
                            <div class="col-4">
                                <div class="border rounded p-2">
                                    <div class="h4 mb-0 text-warning" id="errorCount">0</div>
                                    <small class="text-muted">错误</small>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
                
                <!-- Main Content Area -->
                <div class="col-lg-8">
                    <div class="d-flex justify-content-between align-items-center mb-3">
                        <h4 class="mb-0">
                            <i class="fas fa-list me-2"></i>
                            进程列表
                        </h4>
                        <button class="btn btn-outline-primary btn-sm" onclick="refreshProcessList()">
                            <i class="fas fa-sync-alt me-1"></i>
                            刷新
                        </button>
                    </div>
                    
                    <div id="processList">
                        <div class="text-center text-muted py-5">
                            <i class="fas fa-terminal fa-3x mb-3"></i>
                            <p>暂无进程，请执行一个命令开始使用</p>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
    
    <!-- Toast Container -->
    <div class="toast-container" id="toastContainer"></div>
    
    <!-- Process Detail Modal -->
    <div class="modal fade" id="processModal" tabindex="-1">
        <div class="modal-dialog modal-xl">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title">
                        <i class="fas fa-info-circle me-2"></i>
                        进程详情
                    </h5>
                    <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
                </div>
                <div class="modal-body">
                    <div class="row">
                        <div class="col-md-6">
                            <h6>基本信息</h6>
                            <div id="processInfo"></div>
                        </div>
                        <div class="col-md-6">
                            <h6>实时日志</h6>
                            <div class="log-container" id="processLogs"></div>
                        </div>
                    </div>
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">关闭</button>
                    <button type="button" class="btn btn-danger d-none" id="stopProcessBtn">
                        <i class="fas fa-stop me-1"></i>
                        停止进程
                    </button>
                </div>
            </div>
        </div>
    </div>
    
    <!-- Bootstrap JS -->
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
    
    <script>
        // WebSocket连接
        let stompClient = null;
        let currentProcessId = null;
        
        // 初始化WebSocket连接
        function connectWebSocket() {
            const socket = new SockJS('/ws');
            stompClient = Stomp.over(socket);
            
            stompClient.connect({}, function (frame) {
                console.log('WebSocket连接成功');
                
                // 订阅系统消息（只在这里弹toast）
                stompClient.subscribe('/topic/system', function (message) {
                    showToast('系统消息', message.body, 'info');
                });
                
                // 订阅进程列表更新（不弹toast）
                stompClient.subscribe('/topic/processes', function (message) {
                    const processes = JSON.parse(message.body);
                    updateProcessList(processes);
                });
                
                // 订阅进程状态更新（可选：如需弹toast可在此加）
                stompClient.subscribe('/topic/process/+/status', function (message) {
                    const processId = message.destination.split('/')[3];
                    updateProcessStatus(processId, message.body);
                    // 可选：showToast('进程状态', `进程${processId}状态变更: ${message.body}`);
                });
                
                // 订阅进程日志（只更新日志区，不弹toast）
                stompClient.subscribe('/topic/process/+/logs', function (message) {
                    const processId = message.destination.split('/')[3];
                    const log = JSON.parse(message.body);
                    addProcessLog(processId, log);
                });
            });
        }
        
        // 显示Toast消息
        function showToast(title, message, type = 'info') {
            // 只用于系统消息和操作结果，不用于日志
            const toastContainer = document.getElementById('toastContainer');
            const toast = document.createElement('div');
            toast.className = 'custom-toast';
            const icon = type === 'success' ? 'check-circle' : 
                        type === 'error' ? 'exclamation-circle' : 
                        type === 'warning' ? 'exclamation-triangle' : 'info-circle';
            const color = type === 'success' ? 'text-success' : 
                         type === 'error' ? 'text-danger' : 
                         type === 'warning' ? 'text-warning' : 'text-info';
            toast.innerHTML = `
                <div class="d-flex align-items-center">
                    <i class="fas fa-${icon} ${color} me-2"></i>
                    <div class="flex-grow-1">
                        <div class="fw-bold">${title}</div>
                        <div class="text-muted">${message}</div>
                    </div>
                    <button type="button" class="btn-close" onclick="this.closest('.custom-toast').remove()"></button>
                </div>
            `;
            toastContainer.appendChild(toast);
            setTimeout(() => {
                if (toast.parentElement) {
                    toast.remove();
                }
            }, 3000);
        }
        
        // 设置快速命令
        function setQuickCommand(command, name) {
            document.getElementById('command').value = command;
            document.getElementById('processName').value = name;
        }
        
        // 执行命令
        document.getElementById('commandForm').addEventListener('submit', function(e) {
            e.preventDefault();
            
            const name = document.getElementById('processName').value;
            const command = document.getElementById('command').value;
            const executeBtn = document.getElementById('executeBtn');
            
            if (!name || !command) {
                showToast('错误', '请填写进程名称和命令', 'error');
                return;
            }
            
            executeBtn.disabled = true;
            executeBtn.innerHTML = '<span class="loading-spinner me-2"></span>执行中...';
            
            fetch('/api/processes/execute', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                },
                body: JSON.stringify({ name, command })
            })
            .then(response => response.json())
            .then(data => {
                if (data.processId) {
                    showToast('成功', '命令执行成功', 'success');
                    document.getElementById('commandForm').reset();
                    refreshProcessList();
                } else {
                    showToast('错误', data.message, 'error');
                }
            })
            .catch(error => {
                showToast('错误', '执行命令失败: ' + error.message, 'error');
            })
            .finally(() => {
                executeBtn.disabled = false;
                executeBtn.innerHTML = '<i class="fas fa-rocket me-2"></i>执行命令';
            });
        });
        
        // 刷新进程列表
        function refreshProcessList() {
            fetch('/api/processes')
                .then(response => response.json())
                .then(processes => {
                    updateProcessList(processes);
                })
                .catch(error => {
                    console.error('获取进程列表失败:', error);
                });
        }
        
        // 更新进程列表
        function updateProcessList(processes) {
            const processList = document.getElementById('processList');
            
            if (Object.keys(processes).length === 0) {
                processList.innerHTML = `
                    <div class="text-center text-muted py-5">
                        <i class="fas fa-terminal fa-3x mb-3"></i>
                        <p>暂无进程，请执行一个命令开始使用</p>
                    </div>
                `;
                updateStatistics(processes);
                return;
            }
            
            let html = '';
            Object.entries(processes).forEach(([processId, process]) => {
                const statusClass = getStatusClass(process.status);
                const duration = process.endTime ? 
                    Math.floor((new Date(process.endTime) - new Date(process.startTime)) / 1000) :
                    Math.floor((new Date() - new Date(process.startTime)) / 1000);
                
                html += `
                    <div class="process-card">
                        <div class="process-header">
                            <div class="d-flex justify-content-between align-items-center">
                                <div>
                                    <h6 class="mb-1">${process.name}</h6>
                                    <small class="text-muted">ID: ${process.processId}</small>
                                </div>
                                <div class="d-flex align-items-center gap-2">
                                    <span class="status-badge ${statusClass}">${process.status}</span>
                                    <button class="btn btn-outline-primary btn-sm" onclick="viewProcess('${processId}')">
                                        <i class="fas fa-eye"></i>
                                    </button>
                                    ${process.status === 'RUNNING' ? 
                                        `<button class="btn btn-outline-danger btn-sm" onclick="stopProcess('${processId}')">
                                            <i class="fas fa-stop"></i>
                                        </button>` : ''
                                    }
                                </div>
                            </div>
                        </div>
                        <div class="process-body">
                            <div class="row">
                                <div class="col-md-8">
                                    <code class="text-muted">${process.command}</code>
                                </div>
                                <div class="col-md-4 text-end">
                                    <small class="text-muted">运行时长: ${duration}秒</small>
                                </div>
                            </div>
                        </div>
                    </div>
                `;
            });
            
            processList.innerHTML = html;
            updateStatistics(processes);
        }
        
        // 更新统计信息
        function updateStatistics(processes) {
            let running = 0, stopped = 0, error = 0;
            
            Object.values(processes).forEach(process => {
                switch (process.status) {
                    case 'RUNNING':
                        running++;
                        break;
                    case 'STOPPED':
                        stopped++;
                        break;
                    case 'ERROR':
                        error++;
                        break;
                }
            });
            
            document.getElementById('runningCount').textContent = running;
            document.getElementById('stoppedCount').textContent = stopped;
            document.getElementById('errorCount').textContent = error;
        }
        
        // 获取状态样式类
        function getStatusClass(status) {
            switch (status) {
                case 'RUNNING': return 'status-running';
                case 'STOPPED': return 'status-stopped';
                case 'ERROR': return 'status-error';
                case 'STARTING': return 'status-starting';
                case 'STOPPING': return 'status-stopping';
                default: return 'status-stopped';
            }
        }
        
        // 查看进程详情
        function viewProcess(processId) {
            currentProcessId = processId;
            
            fetch(`/api/processes/${processId}`)
                .then(response => response.json())
                .then(process => {
                    document.getElementById('processInfo').innerHTML = `
                        <table class="table table-sm">
                            <tr><td>进程名称:</td><td>${process.name}</td></tr>
                            <tr><td>进程ID:</td><td>${process.processId}</td></tr>
                            <tr><td>状态:</td><td><span class="status-badge ${getStatusClass(process.status)}">${process.status}</span></td></tr>
                            <tr><td>启动时间:</td><td>${process.startTime}</td></tr>
                            <tr><td>结束时间:</td><td>${process.endTime || '-'}</td></tr>
                            <tr><td>退出码:</td><td>${process.exitCode || '-'}</td></tr>
                            <tr><td>错误信息:</td><td>${process.errorMessage || '-'}</td></tr>
                        </table>
                    `;
                    
                    // 显示日志
                    const logContainer = document.getElementById('processLogs');
                    logContainer.innerHTML = '';
                    process.logs.forEach(log => {
                        addLogEntry(logContainer, log);
                    });
                    
                    // 控制停止按钮显示/隐藏
                    const stopBtn = document.getElementById('stopProcessBtn');
                    if (process.status === 'RUNNING') {
                        stopBtn.classList.remove('d-none');
                    } else {
                        stopBtn.classList.add('d-none');
                    }
                    
                    // 显示模态框
                    new bootstrap.Modal(document.getElementById('processModal')).show();
                })
                .catch(error => {
                    showToast('错误', '获取进程信息失败', 'error');
                });
        }
        
        // 停止进程
        function stopProcess(processId) {
            if (!confirm('确定要停止这个进程吗？')) {
                return;
            }
            
            fetch(`/api/processes/${processId}/stop`, {
                method: 'POST'
            })
            .then(response => response.json())
            .then(data => {
                if (data.message.includes('成功')) {
                    showToast('成功', '进程已停止', 'success');
                    refreshProcessList();
                } else {
                    showToast('错误', data.message, 'error');
                }
            })
            .catch(error => {
                showToast('错误', '停止进程失败', 'error');
            });
        }
        
        // 添加日志条目
        function addLogEntry(container, log) {
            const logEntry = document.createElement('div');
            logEntry.className = 'log-entry';
            
            const timestamp = new Date(log.timestamp).toLocaleTimeString();
            const levelClass = log.level === 'ERROR' ? 'log-level-error' : 
                              log.level === 'WARN' ? 'log-level-warn' : 'log-level-info';
            
            logEntry.innerHTML = `
                <span class="log-timestamp">[${timestamp}]</span>
                <span class="${levelClass}">[${log.level}]</span>
                <span class="log-message">${log.message}</span>
            `;
            
            container.appendChild(logEntry);
            container.scrollTop = container.scrollHeight;
        }
        
        // 添加进程日志
        function addProcessLog(processId, log) {
            if (currentProcessId === processId) {
                const logContainer = document.getElementById('processLogs');
                addLogEntry(logContainer, log);
            }
        }
        
        // 更新进程状态
        function updateProcessStatus(processId, status) {
            // 这里可以更新特定进程的状态显示
            console.log(`进程 ${processId} 状态更新为: ${status}`);
        }
        
        // 网络测试命令参数自动适配
        function getPingCommand() {
            const isWindows = navigator.userAgent.indexOf('Windows') !== -1;
            return isWindows ? 'ping -n 10 www.baidu.com' : 'ping -c 10 www.baidu.com';
        }
        
        // 修改网络测试按钮事件
        document.querySelectorAll('button').forEach(btn => {
            if (btn.textContent.includes('网络测试')) {
                btn.onclick = function() {
                    setQuickCommand(getPingCommand(), '网络测试');
                };
            }
        });
        
        // 页面加载完成后初始化
        document.addEventListener('DOMContentLoaded', function() {
            connectWebSocket();
            refreshProcessList();
            
            // 设置停止进程按钮事件
            document.getElementById('stopProcessBtn').addEventListener('click', function() {
                if (currentProcessId) {
                    stopProcess(currentProcessId);
                    bootstrap.Modal.getInstance(document.getElementById('processModal')).hide();
                }
            });
        });
    </script>
</body>
</html> 